package edu.stanford.bmir.protege.web.server.stkosutil.common.search;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

import org.semanticweb.owlapi.model.EntityType;
import org.semanticweb.owlapi.model.OWLAnnotation;
import org.semanticweb.owlapi.model.OWLDataFactory;
import org.semanticweb.owlapi.model.OWLDataProperty;
import org.semanticweb.owlapi.model.OWLLiteral;
import org.semanticweb.owlapi.model.OWLObjectProperty;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLClass;

import edu.stanford.bmir.protege.web.client.rpc.data.EntityData;
import edu.stanford.bmir.protege.web.client.rpc.data.PaginationData;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.EntityDataComparator;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.SearchCondition;
import edu.stanford.bmir.protege.web.client.rpc.stkosutil.common.UtilEntityType;
import edu.stanford.bmir.protege.web.server.owlapi.OWLAPIProject;
import edu.stanford.bmir.protege.web.server.owlapi.OWLAPIProjectManager;
import edu.stanford.bmir.protege.web.server.owlapi.RenderingManager;
import edu.stanford.bmir.protege.web.shared.project.ProjectId;

public class UtilSearcher {
	 private OWLAPIProject getProject(String projectName) {
	        if (projectName == null) {
	            throw new NullPointerException("projectName must not be null");
	        }
	        ProjectId projectId = ProjectId.get(projectName);
	        // TODO: Log
	        return getProject(projectId);
	    }

	    /**
	     * Gets the OWLAPIProject for a given {@link ProjectId}.If a project with the specified id exists then that project
	     * will be returned, otherwise, a fresh project will be created and that fresh project returned.
	     * @param projectId The id of the project.
	     * @return The OWL API project. Not <code>null</code>.
	     */
	    private OWLAPIProject getProject(ProjectId projectId) {
	        OWLAPIProjectManager pm = OWLAPIProjectManager.getProjectManager();
	        return pm.getProject(projectId);
	    }
	 //******************* 
	public PaginationData<EntityData> search(String projectName, SearchCondition searchCondition,  int start, int limit, String sort, String dir){
		return null;
	}
	public List<EntityData> search(String projectName, SearchCondition searchCondition){
		if (searchCondition.getEntityType()==UtilEntityType.CLASS){
			return this.searchClassByMappingNo(projectName, searchCondition);
		}else if (searchCondition.getEntityType()==UtilEntityType.ANY_PROPERTY){
			List<EntityData> objectPropertyList = this.searchObjectPropertyByMappingNo(projectName, searchCondition);
			List<EntityData> dataPropertyList = this.searchDataPropertyByMappingNo(projectName, searchCondition);
			objectPropertyList.addAll(dataPropertyList);
			return objectPropertyList;
		}else{
			return null;
		}
	}
	
	private List<EntityData> searchClassByMappingNo(String projectName, SearchCondition searchCondition){
		UtilMatcher utilMatcher = new UtilMatcher();
		List<EntityData> result = new ArrayList<EntityData>();
		OWLAPIProject project = this.getProject(projectName);
		OWLOntology o = project.getRootOntology();
		OWLDataFactory df = project.getDataFactory();
		RenderingManager rm = project.getRenderingManager();
		for (OWLClass cls : o.getClassesInSignature()) {
			// Get the annotations on the class that use the label property
			for (OWLAnnotation annotation : cls.getAnnotations(o, df.getRDFSComment())) {
				if (annotation.getValue() instanceof OWLLiteral) {
					OWLLiteral val = (OWLLiteral) annotation.getValue();
					String comment = val.getLiteral();
					boolean matched = utilMatcher.matchSearchCondition(comment, searchCondition);
					// look for portuguese labels
					if (matched){
						EntityData entityData = rm.getEntityData(cls);
	                    result.add(entityData);
					}
				}
			}
		}
		EntityDataComparator comparator = new EntityDataComparator();
		Collections.sort(result, comparator);
		return result;
	}
	private List<EntityData> searchObjectPropertyByMappingNo(String projectName, SearchCondition searchCondition){
		UtilMatcher utilMatcher = new UtilMatcher();
		List<EntityData> result = new ArrayList<EntityData>();
		OWLAPIProject project = this.getProject(projectName);
		OWLOntology o = project.getRootOntology();
		OWLDataFactory df = project.getDataFactory();
		RenderingManager rm = project.getRenderingManager();
		for (OWLObjectProperty property : o.getObjectPropertiesInSignature()) {
			// Get the annotations on the class that use the label property
			for (OWLAnnotation annotation : property.getAnnotations(o, df.getRDFSComment())) {
				if (annotation.getValue() instanceof OWLLiteral) {
					OWLLiteral val = (OWLLiteral) annotation.getValue();
					String comment = val.getLiteral();
					boolean matched = utilMatcher.matchSearchCondition(comment, searchCondition);
					// look for portuguese labels
					if (matched){
						EntityData entityData = rm.getEntityData(property);
	                    result.add(entityData);
					}
				}
			}
		}
		EntityDataComparator comparator = new EntityDataComparator();
		Collections.sort(result, comparator);
		return result;
	}
	private List<EntityData> searchDataPropertyByMappingNo(String projectName, SearchCondition searchCondition){
		UtilMatcher utilMatcher = new UtilMatcher();
		List<EntityData> result = new ArrayList<EntityData>();
		OWLAPIProject project = this.getProject(projectName);
		OWLOntology o = project.getRootOntology();
		OWLDataFactory df = project.getDataFactory();
		RenderingManager rm = project.getRenderingManager();
		for (OWLDataProperty property : o.getDataPropertiesInSignature()) {
			// Get the annotations on the class that use the label property
			for (OWLAnnotation annotation : property.getAnnotations(o, df.getRDFSComment())) {
				if (annotation.getValue() instanceof OWLLiteral) {
					OWLLiteral val = (OWLLiteral) annotation.getValue();
					String comment = val.getLiteral();
					boolean matched = utilMatcher.matchSearchCondition(comment, searchCondition);
					// look for portuguese labels
					if (matched){
						EntityData entityData = rm.getEntityData(property);
	                    result.add(entityData);
					}
				}
			}
		}
		EntityDataComparator comparator = new EntityDataComparator();
		Collections.sort(result, comparator);
		return result;
	}
}
